/*
 * FaceCat图形通讯框架
 * 著作权编号:2015SR229355+2020SR0266727
 * 上海卷卷猫信息技术有限公司
 */

#include "stdafx.h"
#include "FCServerService.h"
#include "FCBinary.h"
#include "FCServerSockets.h"

namespace FaceCat{
    long long m_downFlow2 = 0;

    long long m_upFlow2 = 0;

    MessageCallBack m_messageCallBack2;

    ArrayList<FCServerService*> m_services2;

    ArrayList<FCDataEventCallBack*> m_serverDataCallBacks;

    FCLock m_serverDataCallBacksLock;

    WriteLogCallBack m_writeLogCallBack2;

    int FCServerService::closeServer(int socketID){
        return FCServerSockets::close(socketID);
    }

    void FCServerService::registerCallBack(MessageCallBack callBack){
        FCServerSockets::registerRecv(callBack);
    }

    void FCServerService::registerLog(WriteLogCallBack callBack){
        FCServerSockets::registerLog(callBack);
    }

    int FCServerService::sendByServer(int socketID, const char *str, int len){
        return FCServerSockets::send(socketID, str, len);
    }

    int FCServerService::startServer(int port, char* token){
        return FCServerSockets::start(port, token);
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    FCServerService::FCServerService(){
        m_compressType = COMPRESSTYPE_NONE;
        m_serviceID = 0;
        m_socketID = -1;
    }

    FCServerService::~FCServerService(){
        m_lock.lock();
        m_listeners.clear();
        m_waitMessages.clear();
        m_lock.unLock();
    }

    int FCServerService::getCompressType(){
        return 1;
    }

    void FCServerService::setCompressType(int value){
        m_compressType = value;
    }

    long long FCServerService::getDownFlow(){
        return m_downFlow2;
    }

    void FCServerService::setDownFlow(long long value){
        m_downFlow2 = value;
    }

    int FCServerService::getServiceID(){
        return m_serviceID;
    }

    void FCServerService::setServiceID(int value){
        m_serviceID = value;
    }

    int FCServerService::getSocketID(){
        return m_socketID;
    }

    void FCServerService::setSocketID(int value){
        m_socketID = value;
    }

    long long FCServerService::getUpFlow(){
        return m_upFlow2;
    }

    void FCServerService::setUpFlow(long long value){
        m_upFlow2 = value;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    void FCServerService::addDataCallBack(FCDataEventCallBack *dataCallBack){
        m_serverDataCallBacksLock.lock();
        m_serverDataCallBacks.add(dataCallBack);
        m_serverDataCallBacksLock.unLock();
    }

    void FCServerService::addService(FCServerService *service){
        if (!m_messageCallBack2){
            MessageCallBack messageCallBack = &callBack;
            m_messageCallBack2 = messageCallBack;
            registerCallBack(messageCallBack);
            WriteLogCallBack writeLogCallBack = &writeServerLog;
            m_writeLogCallBack2 = writeLogCallBack;
            registerLog(m_writeLogCallBack2);
        }
        m_services2.add(service);
    }

    void FCServerService::callBack(int socketID, int localSID, const char *str, int len){
        m_downFlow2 += len;
        if(m_serverDataCallBacks.size() > 0){
            m_serverDataCallBacksLock.lock();
            for(int i = 0; i < m_serverDataCallBacks.size(); i++){
                if(m_serverDataCallBacks.get(i)->callDataEvent(socketID, localSID, str, len)){
                    m_serverDataCallBacksLock.unLock();
                    return;
                }
            }
            m_serverDataCallBacksLock.unLock();
        }
        if (len > 4){
            FCBinary binary;
            binary.write(str, len);
            int head = binary.readInt();
            int serviceID = (int)binary.readShort();
            FCServerService *service = 0;
            int matchCount = 0;
            for(int i = 0; i < m_services2.size(); i++){
                FCServerService *serverService = m_services2.get(i);
                if(serverService->getServiceID() == serviceID){
                    if(matchCount > 0){
                        FCBinary brNew;
                        brNew.write(str, len);
                        brNew.readInt();
                        brNew.readShort();
                        serverService->onCallBack(&brNew, socketID, localSID, len);
                    }else{
                        serverService->onCallBack(&binary, socketID, localSID, len);
                    }
                    matchCount++;
                }
            }
        }
    }

    int FCServerService::getRequestID(){
        return m_requestID ++;
    }

    void FCServerService::getServices(ArrayList<FCServerService*> *services){
        for(int i = 0; i < m_services2.size(); i++){
            services->add(m_services2.get(i));
        }
    }

    int FCServerService::keepAlive(int socketID){
        FCBinary binary;
        binary.initialize(4, false);
        binary.writeInt(4);
        char *str = (char*)binary.getBytes();
        return sendByServer(socketID, str, 4);
    }

    void FCServerService::onCallBack(FCBinary *binary, int socketID, int localSID, int len){
        int headSize = sizeof(int) * 3 + sizeof(short) * 2 + 1 * 2;
        int functionID = (int)binary->readShort();
        int requestID = binary->readInt();
        int state = (int)binary->readChar();
        int compressType = (int)binary->readChar();
        int uncBodyLength = binary->readInt();
        int bodyLength = len - headSize;
        char *body = new char[bodyLength];
        memset(body, '\0', bodyLength);
        binary->read(body, bodyLength);
        /*if (compressType == COMPRESSTYPE_GZIP){
            uLong deLen = uncBodyLength;
            char *buffer = new char[deLen];
            memset(buffer, '\0', deLen);
            FCTran::gZDeCompress((Byte*)body, bodyLength, (Byte*)buffer, &deLen);
            delete[] body;
            body = buffer;
        }*/
        FCMessage message(getServiceID(), functionID, requestID, socketID, state, compressType, uncBodyLength, body);
        onReceive(&message);
        onWaitMessageHandle(&message);
        if(message.m_body){
            delete[] body;
        }
        body = 0;
    }

    void FCServerService::onClientClose(int socketID, int localSID){
        m_lock.lock();
        if(m_compressTypes.containsKey(socketID)){
            m_compressTypes.remove(socketID);
        }
        m_lock.unLock();
    }

    void FCServerService::onClientConnect(int socketID, int localSID, String ip){
    }

    void FCServerService::onReceive(FCMessage *message){
        m_lock.lock();
        m_compressTypes.put(message->m_socketID, message->m_compressType);
        m_lock.unLock();
    }

    void FCServerService::onWaitMessageHandle(FCMessage *message){
        if((int)m_waitMessages.size() > 0){
            m_lock.lock();
            if(m_waitMessages.containsKey(message->m_requestID)){
                FCMessage *waitMessage = m_waitMessages.get(message->m_requestID);
                waitMessage->copy(message);
                char *newBody = new char[message->m_bodyLength];
                for (int i = 0; i < message->m_bodyLength; i++){
                    newBody[i] = message->m_body[i];
                }
                waitMessage->m_body = newBody;
            }
            m_lock.unLock();
        }
    }

    void FCServerService::addWait(int requestID, FCMessage *message){
        m_lock.lock();
        m_waitMessages.put(requestID, message);
        m_lock.unLock();
    }

    void FCServerService::addListener(int requestID, FCListenerMessageCallBack *callBack, Object pInvoke){
        m_lock.lock();
        FCMessageListener *listener = 0;
        if(m_listeners.containsKey(requestID)){
            listener = m_listeners.get(requestID);
        }
        else{
            listener = new FCMessageListener;
            m_listeners.put(requestID, listener);
        }
        listener->add(callBack, pInvoke);
        m_lock.unLock();
    }

    int FCServerService::send(FCMessage *message){
        FCBinary binary;
        char *buffer = 0;
        const char *body = message->m_body;
        int bodyLength = message->m_bodyLength;
        int uncBodyLength = bodyLength;
        /*if(uncBodyLength >= 32){
            m_lock.lock();
            if(m_compressTypes.containsKey(message->m_socketID)){
                message->m_compressType = m_compressTypes.get(message->m_socketID);
            }
            m_lock.unLock();
            if (message->m_compressType == COMPRESSTYPE_GZIP){
                uLong cLen = 32;
                if(uncBodyLength > cLen)
                {
                    cLen = uncBodyLength;
                }
                buffer = new char[cLen];
                memset(buffer, '\0', cLen);
                FCTran::gZCompress((Byte*)body, bodyLength, (Byte*)buffer, &cLen);
                body = buffer;
                bodyLength = (int)cLen;
            }
        }else{
            message->m_compressType = COMPRESSTYPE_NONE;
        }*/
        int len = sizeof(int) * 3 + bodyLength + sizeof(short) * 2 + sizeof(char) * 2;
        binary.initialize(len, false);
        binary.writeInt(len);
        binary.writeShort((short)message->m_serviceID);
        binary.writeShort((short)message->m_functionID);
        binary.writeInt(message->m_requestID);
        binary.writeChar((char)message->m_state);
        binary.writeChar((char)message->m_compressType);
        binary.writeInt(uncBodyLength);
        binary.write(body, bodyLength);
        char *str = (char*)binary.getBytes();
        if(buffer){
            delete[] buffer;
            buffer = 0;
        }
        int ret = sendByServer(message->m_socketID, str, len);
        m_upFlow2 += ret;
        return ret;
    }

    void FCServerService::sendToListener(FCMessage *message){
        FCMessageListener *listener = 0;
        m_lock.lock();
        if(m_listeners.containsKey(message->m_requestID)){
            listener = m_listeners.get(message->m_requestID);
        }
        m_lock.unLock();
        if(listener){
            listener->callBack(message);
        }
    }

    void FCServerService::removeDataCallBack(FCDataEventCallBack *dataCallBack){
        m_serverDataCallBacksLock.lock();
        int size = m_serverDataCallBacks.size();
        for(int i = 0; i < size; i++){
            if(m_serverDataCallBacks.get(i) == dataCallBack){
                m_serverDataCallBacks.removeAt(i);
                i--;
                size--;
            }
        }
        m_serverDataCallBacksLock.unLock();
    }

    void FCServerService::removeListener(int requestID){
        m_lock.lock();
        if(m_listeners.containsKey(requestID)){
            m_listeners.remove(requestID);
        }
        m_lock.unLock();
    }

    void FCServerService::removeListener(int requestID, FCListenerMessageCallBack *callBack){
        m_lock.lock();
        if(m_listeners.containsKey(requestID)){
            m_listeners.get(requestID)->remove(callBack);
        }
        m_lock.unLock();
    }

    void FCServerService::removeWait(int requestID){
        m_lock.lock();
        if(m_waitMessages.containsKey(requestID)){
            m_waitMessages.remove(requestID);
        }
        m_lock.unLock();
    }

    int FCServerService::waitMessage(int requestID, int timeout){
        int state = 0;
        while(timeout > 0){
            m_lock.lock();
            if(m_waitMessages.containsKey(requestID)){
                FCMessage *message = m_waitMessages.get(requestID);
                if(message->m_bodyLength > 0){
                    state = 1;
                    m_lock.unLock();
                    break;
                }
            }
            else{
                m_lock.unLock();
                break;
            }
            m_lock.unLock();
            timeout -= 10;
            usleep(10000);
        }
        removeWait(requestID);
        return state;
    }

    void FCServerService::writeServerLog(int socketID, int localSID, int state, const char *log){
        if (state == 2 || state == 3) {
            for(int i = 0; i < m_services2.size(); i++){
                FCServerService *service = m_services2.get(i);
                service->onClientClose(socketID, localSID);
            }
        } else if (state == 1) {
            for(int i = 0; i < m_services2.size(); i++){
                FCServerService *service = m_services2.get(i);
                service->onClientConnect(socketID, localSID, FCTran::stringToString(log));
            }
        }
    }
}

